//
//  AudioRecorderManager.swift
//  GLUZSwift
//
//  Created by xyanl on 2025/5/12.
//

import UIKit
import AVFoundation
import Foundation

// MARK: - 错误类型枚举

/// 录音过程中可能出现的错误类型
enum AudioRecorderError: Error {
    case permissionDenied               // 用户拒绝了录音权限
    case sessionConfigurationFailed     // 音频会话配置失败
    case recorderSetupFailed            // 录音器初始化失败
    case fileOperationFailed            // 文件操作失败
    case invalidRecorderState           // 录音器状态无效
    case inputGainAdjustmentFailed      // 输入增益调整失败
    case microphoneSelectionFailed      // 麦克风选择失败
}

// MARK: - 录音器委托协议

/// 录音器状态回调协议
protocol AudioRecorderManagerDelegate: AnyObject {
    /// 录音开始回调
    func recorderDidStart()
    /// 录音暂停回调
    func recorderDidPause()
    /// 录音继续回调
    func recorderDidResume()
    /// 录音完成回调
    /// - Parameters:
    ///   - success: 是否成功完成
    ///   - fileURL: 录音文件保存路径（成功时有效）
    func recorderDidFinish(_ success: Bool, fileURL: URL?)
    /// 录音失败回调
    /// - Parameter error: 错误对象
    func recorderDidFail(with error: Error)
    /// 录音电平实时更新
    /// - Parameters:
    ///   - averagePower: 平均电平值（单位：分贝，范围：-160到0）
    ///   - peakPower: 峰值电平值（单位：分贝，范围：-160到0）
    func recorderDidUpdateMeter(_ averagePower: Float, peakPower: Float)
    /// 输入增益变化回调
    /// - Parameter gain: 当前输入增益值（范围：0.0到1.0）
    func inputGainDidChange(_ gain: Float)
}

// MARK: - 录音功能主类

/// 功能完整的录音封装类
final class AudioRecorderManager: NSObject {
    
    // MARK: - 私有属性
    
    private var audioRecorder: AVAudioRecorder?   // 核心录音器实例
    private var audioSession: AVAudioSession!     // 音频会话
    private var audioPlayer: AVAudioPlayer?      // 播放器实例（用于播放录音）
    private var meterTimer: Timer?                // 电平测量定时器
    private var currentRecordingURL: URL?         // 当前录音文件路径
    private var isMonitoringInputGain = false    // 是否正在监控输入增益
    
    // MARK: - 公开属性
    
    /// 录音器委托对象
    weak var delegate: AudioRecorderManagerDelegate?
    
    /// 当前是否正在录音
    var isRecording: Bool {
        return audioRecorder?.isRecording ?? false
    }
    
    /// 当前是否处于暂停状态
    private(set) var isPaused: Bool = false
    
    /// 当前输入增益值（范围：0.0到1.0）
    var currentInputGain: Float {
        return audioSession.inputGain
    }
    
    /// 获取所有录音文件的URL数组（按创建时间排序）
    var allRecordings: [URL] {
        return getAllRecordings()
    }
    
    // MARK: - 初始化方法
    
    override init() {
        super.init()
        configureAudioSession()
    }
    
    deinit {
        // 清理资源
        stopMonitoringInputGain()
        meterTimer?.invalidate()
        try? audioSession.setActive(false)
    }
    
    // MARK: - 音频会话配置
    
    /// 配置音频会话
    private func configureAudioSession() {
        audioSession = AVAudioSession.sharedInstance()
        
        do {
            // 配置音频会话类别
            // .playAndRecord: 支持录音和播放
            // .default: 默认模式
            // options: 允许蓝牙设备，默认使用扬声器
            try audioSession.setCategory(
                .playAndRecord,
                mode: .default,
                policy: .default,
                options: [.allowBluetooth, .defaultToSpeaker]
            )
            
            // 激活音频会话
            try audioSession.setActive(true)
            
            // 开始监控输入增益变化
            startMonitoringInputGain()
            
        } catch {
            delegate?.recorderDidFail(with: AudioRecorderError.sessionConfigurationFailed)
        }
    }
    
    // MARK: - 录音控制
    
    /// 开始录音
    /// - Parameters:
    ///   - fileName: 自定义文件名（不需要扩展名）
    ///   - fileExtension: 文件扩展名（默认m4a）
    /// - Throws: 可能抛出AudioRecorderError错误
    func startRecording(fileName: String = "recording", fileExtension: String = "m4a") throws {
        // 检查当前状态
        guard !isRecording else {
            throw AudioRecorderError.invalidRecorderState
        }
        
        // 请求录音权限
        audioSession.requestRecordPermission { [weak self] granted in
            guard let self = self else { return }
            
            DispatchQueue.main.async {
                if granted {
                    do {
                        // 设置录音器
                        try self.setupRecorder(fileName: fileName, fileExtension: fileExtension)
                        
                        // 选择最佳麦克风
                        try self.selectOptimalMicrophone()
                        
                        // 开始录音
                        self.audioRecorder?.record()
                        
                        // 开始电平测量
                        self.startMetering()
                        
                        // 通知委托对象
                        self.delegate?.recorderDidStart()
                        
                    } catch {
                        self.delegate?.recorderDidFail(with: error)
                    }
                } else {
                    self.delegate?.recorderDidFail(with: AudioRecorderError.permissionDenied)
                }
            }
        }
    }
    
    /// 暂停录音
    /// - Throws: 可能抛出AudioRecorderError错误
    func pauseRecording() throws {
        guard isRecording, !isPaused else {
            throw AudioRecorderError.invalidRecorderState
        }
        
        audioRecorder?.pause()
        isPaused = true
        stopMetering()
        delegate?.recorderDidPause()
    }
    
    /// 继续录音
    /// - Throws: 可能抛出AudioRecorderError错误
    func resumeRecording() throws {
        guard !isRecording, isPaused else {
            throw AudioRecorderError.invalidRecorderState
        }
        
        audioRecorder?.record()
        isPaused = false
        startMetering()
        delegate?.recorderDidResume()
    }
    
    /// 停止录音
    /// - Throws: 可能抛出AudioRecorderError错误
    func stopRecording() throws {
        guard isRecording || isPaused else {
            throw AudioRecorderError.invalidRecorderState
        }
        
        audioRecorder?.stop()
        isPaused = false
        stopMetering()
        
        // 重置音频会话，避免影响其他音频功能
        try audioSession.setActive(false, options: .notifyOthersOnDeactivation)
    }
    
    // MARK: - 录音器设置
    
    /// 设置录音器
    /// - Parameters:
    ///   - fileName: 文件名（不含扩展名）
    ///   - fileExtension: 文件扩展名
    /// - Throws: 可能抛出AudioRecorderError错误
    private func setupRecorder(fileName: String, fileExtension: String) throws {
        // 生成带时间戳的唯一文件名
        let timestamp = Date().timeIntervalSince1970
        let uniqueFileName = "\(fileName)_\(Int(timestamp))"
        
        // 构建文件保存路径
        let documentsDirectory = FileManager.default.urls(
            for: .documentDirectory,
            in: .userDomainMask
        )[0]
        
        let fileURL = documentsDirectory.appendingPathComponent("\(uniqueFileName).\(fileExtension)")
        currentRecordingURL = fileURL
        
        // 录音设置（针对不同格式优化）
        var settings: [String: Any] = [
            AVSampleRateKey: 44100.0,               // 采样率
            AVNumberOfChannelsKey: 2,               // 声道数
            AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue  // 音质
        ]
        
        // 根据文件格式调整参数
        switch fileExtension.lowercased() {
        case "wav", "aif", "aiff":
            settings[AVFormatIDKey] = kAudioFormatLinearPCM
            settings[AVLinearPCMBitDepthKey] = 16
            settings[AVLinearPCMIsFloatKey] = false
            settings[AVLinearPCMIsBigEndianKey] = false
        case "m4a", "mp4":
            settings[AVFormatIDKey] = kAudioFormatMPEG4AAC
            settings[AVEncoderBitRateKey] = 128000  // 128kbps比特率
        default:
            settings[AVFormatIDKey] = kAudioFormatMPEG4AAC
        }
        
        do {
            // 创建录音器实例
            audioRecorder = try AVAudioRecorder(url: fileURL, settings: settings)
            audioRecorder?.delegate = self
            audioRecorder?.isMeteringEnabled = true  // 启用电平测量
            audioRecorder?.prepareToRecord()         // 预准备录音
        } catch {
            throw AudioRecorderError.recorderSetupFailed
        }
    }
    
    // MARK: - 录音播放
    
    /// 播放指定URL的录音文件
    /// - Parameter url: 录音文件URL
    /// - Throws: 可能抛出播放错误
    func playRecording(at url: URL) throws {
        // 停止当前播放（如果有）
        audioPlayer?.stop()
        
        // 创建并准备播放器
        audioPlayer = try AVAudioPlayer(contentsOf: url)
        audioPlayer?.prepareToPlay()
        audioPlayer?.play()
    }
    
    /// 停止播放录音
    func stopPlayback() {
        audioPlayer?.stop()
    }
    
    // MARK: - 麦克风选择
    
    /// 选择最佳麦克风
    private func selectOptimalMicrophone() throws {
        guard let inputs = audioSession.availableInputs else { return }
        
        // 优先选择内置麦克风（而非耳机麦克风）
        if let builtInMic = inputs.first(where: { $0.portType == .builtInMic }) {
            try audioSession.setPreferredInput(builtInMic)
        }
        
        // 在iPhone上，选择底部麦克风（主麦克风）
        if let dataSources = audioSession.preferredInput?.dataSources {
            if let bottomDataSource = dataSources.first(where: {
                $0.dataSourceName.lowercased().contains("bottom")
            }) {
                try audioSession.preferredInput?.setPreferredDataSource(bottomDataSource)
            }
        }
    }
    
    // MARK: - 输入增益控制
    
    /// 调整输入增益
    /// - Parameter gain: 增益值（范围：0.0到1.0）
    /// - Throws: 可能抛出AudioRecorderError错误
    func setInputGain(_ gain: Float) throws {
        let clampedGain = max(0.0, min(gain, 1.0))  // 确保在有效范围内
        
        do {
            try audioSession.setInputGain(clampedGain)
            delegate?.inputGainDidChange(clampedGain)
        } catch {
            throw AudioRecorderError.inputGainAdjustmentFailed
        }
    }
    
    /// 开始监控输入增益变化
    private func startMonitoringInputGain() {
        guard !isMonitoringInputGain else { return }
        
        isMonitoringInputGain = true
        //        NotificationCenter.default.addObserver(
        //            self,
        //            selector: #selector(inputGainChanged),
        //            name: AVAudioSessionInputGainDidChange,
        //            object: nil
        //        )
    }
    
    /// 停止监控输入增益变化
    private func stopMonitoringInputGain() {
        guard isMonitoringInputGain else { return }
        
        isMonitoringInputGain = false
        //        NotificationCenter.default.removeObserver(
        //            self,
        //            name: AVAudioSession.inputGainChangeNotification,
        //            object: nil
        //        )
    }
    
    /// 输入增益变化回调
    @objc private func inputGainChanged() {
        delegate?.inputGainDidChange(currentInputGain)
    }
    
    // MARK: - 音频电平测量
    
    /// 开始电平测量
    private func startMetering() {
        meterTimer?.invalidate()
        meterTimer = Timer.scheduledTimer(
            withTimeInterval: 0.1,  // 每100ms更新一次
            repeats: true
        ) { [weak self] _ in
            guard let self = self, let recorder = self.audioRecorder else { return }
            
            // 更新电平数据
            recorder.updateMeters()
            
            // 获取电平值
            let averagePower = recorder.averagePower(forChannel: 0)
            let peakPower = recorder.peakPower(forChannel: 0)
            
            // 自动增益控制逻辑
            if averagePower < -30.0 {  // 如果音量太低
                do {
                    let currentGain = self.currentInputGain
                    let newGain = min(currentGain + 0.05, 1.0)  // 小幅增加增益
                    try self.setInputGain(newGain)
                } catch {
                    print("自动增益调整失败: \(error)")
                }
            }
            
            // 通知委托对象
            self.delegate?.recorderDidUpdateMeter(averagePower, peakPower: peakPower)
        }
    }
    
    /// 停止电平测量
    private func stopMetering() {
        meterTimer?.invalidate()
        meterTimer = nil
    }
    
    // MARK: - 文件管理
    
    /// 获取所有录音文件
    /// - Returns: 按创建时间排序的录音文件URL数组
    private func getAllRecordings() -> [URL] {
        let documentsDirectory = FileManager.default.urls(
            for: .documentDirectory,
            in: .userDomainMask
        )[0]
        
        do {
            let directoryContents = try FileManager.default.contentsOfDirectory(
                at: documentsDirectory,
                includingPropertiesForKeys: [.creationDateKey],
                options: []
            )
            
            // 过滤出支持的音频文件
            let audioFiles = directoryContents.filter { url in
                let ext = url.pathExtension.lowercased()
                return ["m4a", "wav", "aac", "mp4", "aif", "aiff"].contains(ext)
            }
            
            // 按创建时间排序（最新的在前）
            return audioFiles.sorted {
                let date1 = try? $0.resourceValues(forKeys: [.creationDateKey]).creationDate
                let date2 = try? $1.resourceValues(forKeys: [.creationDateKey]).creationDate
                return (date1 ?? Date()) > (date2 ?? Date())
            }
            
        } catch {
            delegate?.recorderDidFail(with: error)
            return []
        }
    }
    
    /// 删除录音文件
    /// - Parameter url: 要删除的文件URL
    /// - Throws: 可能抛出AudioRecorderError错误
    func deleteRecording(at url: URL) throws {
        guard FileManager.default.fileExists(atPath: url.path) else {
            throw AudioRecorderError.fileOperationFailed
        }
        
        do {
            try FileManager.default.removeItem(at: url)
        } catch {
            throw AudioRecorderError.fileOperationFailed
        }
    }
    
    /// 获取录音文件时长（秒）
    /// - Parameter url: 录音文件URL
    /// - Returns: 文件时长（秒）
    func durationOfRecording(at url: URL) -> TimeInterval? {
        let audioAsset = AVURLAsset(url: url)
        return TimeInterval(CMTimeGetSeconds(audioAsset.duration))
    }
}

// MARK: - AVAudioRecorderDelegate 扩展

extension AudioRecorderManager: AVAudioRecorderDelegate {
    func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {
        delegate?.recorderDidFinish(flag, fileURL: flag ? currentRecordingURL : nil)
        currentRecordingURL = nil
    }
    
    func audioRecorderEncodeErrorDidOccur(_ recorder: AVAudioRecorder, error: Error?) {
        if let error = error {
            delegate?.recorderDidFail(with: error)
        }
        currentRecordingURL = nil
    }
}
